﻿using System;
using ParboiledSharp.parboiled.dataobjects;

namespace ParboiledSharp.parboiled.rules
{
    abstract class Rule
    {
        private object[] _rules;

        public virtual void EndRule(bool result, Context context) { }

        internal abstract bool Execute(Context context);

        public Rule SetRules(params object[] rules)
        {
            for (int i = 0; i < rules.Length; i++)
            {
                rules[i] = ProcessRule(rules[i]);
            }

            _rules = rules;
            return this;
        }

        public Rule SetRule(object rule)
        {
            _rules = new[] { ProcessRule(rule) };
            return this;
        }

        private static object ProcessRule(object rule)
        {
            if (rule is string)
            {
                return new StringRule((string)rule, false);
            }
            else if(rule is Char){
                return new StringRule(""+(char)rule, false);
            }

            return rule;
        }

        internal object[] GetRules()
        {
            return _rules;
        }

        internal object GetRule()
        {
            return _rules[0];
        }

        virtual protected bool ExecuteRule(object rule, Context context)
        {
            if (rule == null)
            {
                return false;
            }

            if (rule is Rule)
            {
                return ((Rule)rule).Execute(context);
            }

            if (rule is Boolean)
            {
                return (Boolean)rule;
            }

            if (rule is Func<Boolean>)
            {
                Func<Context, bool> f = (Func<Context, bool>)rule;
                return f.Invoke(context);
            }

            throw new Exception("Rule should return boolean value");
        }
    }
}
